<?php

namespace App\Service\VendorClient\ShopYouZanApi;

use App\Model\PssLogModel\MicroServiceLog;
use App\Model\PssModel\PddToken;
use App\Service\BaseService;
use App\Service\Code\Normal;
use App\Service\HttpRequest\Http;

class ShopYouZanApiClient extends BaseService
{
    //目前只有一个有赞应用,所以配置暂时写死
    private $clientId = '989d5c55a5fd8bf6ca';
    private $clientSecret = 'ad8f92899b958adc9753bbc5a316c514';
    private $apiUrl = 'https://open.youzanyun.com/api';
    private $authUrl = 'https://open.youzanyun.com/auth/token';
    //路由
    private $routeMaps = [
        'queryOrder'            => '/youzan.trades.sold.get/4.0.1',
        'queryGoodsDetail'      => '/youzan.item.get/3.0.0',
        'addGoodsHaiTao'        => '/youzan.item.create.haitao/1.0.0',
        'editGoodsHaiTao'       => '/youzan.item.update.haitao/1.0.0',
        'addGoods'              => '/youzan.item.add/1.0.1',
        'editGoods'             => '/youzan.item.incremental.update/1.0.1',
        'orderSingleExpress'    => '/youzan.logistics.online.confirm/3.0.0',
        'orderBatchExpress'     => '/youzan.trade.dc.delivery.ordersingleitemsend/3.0.2',
        'delGoods'              => '/youzan.item.update.delisting/3.0.1',
        'reportPayment'         => '/youzan.pay.customs.declaration.reportpayment.report/1.0.1',
        'queryOrderDetail'      => '/youzan.trade.get/4.0.0',
        'checkPayDeclare'       => '/youzan.pay.customs.declaration.reportpayment.query/1.0.1',
        'queryHaiTaoGoods'      => '/youzan.item.get.haitao/1.0.0',
        'getTradeRefundOld'     => '/youzan.trade.refund.get/3.0.0',
        'getTradeRefund'        => '/youzan.trade.refund.get/3.0.1',
        'uploadImg'             => '/youzan.materials.storage.platform.img.upload/3.0.0',
        'updateQuantity'        => '/youzan.item.quantity.update/3.0.0'
    ];
    private $header = [
        "Content-Type: application/json",
        "Accept:application/json"
    ];
    const TOKEN_PREFIX = 'youzan_api_access_token_';

    //授权绑定
    public function authorizationCode($code)
    {
        $params = [
            'data' => [
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'authorize_type' => 'authorization_code',
                'code' => $code,
            ]
        ];
        return $this->executeAuth($params);
    }

    //授权绑定
    public function refreshToken($token)
    {
        $params = [
            'data' => [
                'client_id' => $this->clientId,
                'client_secret' =>  $this->clientSecret,
                'authorize_type' => 'refresh_token',
                'refresh_token' => $token,
            ] 
        ];
        return $this->executeAuth($params);
    }

    /**
     * 支付单申报
     * @param $params
     */
    public function reportPayment($params, $is_cut = false)
    {
        //解密数据
        $decodeData = json_decode(urldecode($params['msg']), true);
        $fullOrderInfo = $decodeData['full_order_info'];

        //拼接申报需要的数据
        $amount = 0;
        foreach ($fullOrderInfo['orders'] as $order) {
            $amount = bcadd($amount, bcadd($order['payment'], $order['freight'], 2), 2);
        }

        $firstOrder = reset($fullOrderInfo['orders']);

        $orderInfo = $fullOrderInfo['order_info'];
        /**
         * 判断是否为分销商订单
         * 主订单类型 0:普通订单; 1:送礼订单; 2:代付; 3:供货商查询时返回表示为分销供货单。; 4:赠品; 5:心愿单; 6:二维码订单; 7:合并付货款; 8:1分钱实名认证; 9:品鉴; 10:拼团; 15:返利; 35:酒店; 40:外卖; 41:堂食点餐; 46:外卖买单; 51:全员开店; 61:线下收银台订单; 71:美业预约单; 72:美业服务单; 75:知识付费; 81:礼品卡;85：直播带货订单（仅指爱逛平台产生的订单） 100:批发   
         */
        if ($orderInfo['type'] == 3) {
            $transaction = $orderInfo['order_extra']['fx_inner_transaction_no'];
            $tid         = $orderInfo['order_extra']['fx_order_no'];
        } else {
            $transaction = $fullOrderInfo['pay_info']['transaction'][0];
            $tid         = $orderInfo['tid'];
        }

        $request_params = [
            'tid' => $tid, //主单号
            'transaction' => $transaction, //支付流水号
            'action_type' => 1,  //报关类型 默认值：1，当前仅支持传值1，重推也是使用1
            'customs_code' => $firstOrder['customs_code'], //关区编码
            'kdt_id' => $params['kdt_id'], //店铺id
        ];

        if ($is_cut) {
            $request_params = array_merge(
                $request_params,
                [
                    'amount' => bcmul($amount, 100),
                    'sub_order_no' => $firstOrder['sub_order_no'],
                    'currency' => 'CNY'
                ]
            );
        }

        return $this->execute([
            'data'    => $request_params,
            'method'  => 'reportPayment',
            'storeID' => $params['kdt_id']
        ]);
    }

    /**
     * 获取售后单
     * @param $params
     */
    public function getTradeRefund($refund_id, $kdt_id)
    {
        $request_params = [
            'refund_id' => $refund_id
        ];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'getTradeRefund',
            'storeID' => $kdt_id
        ]);
    }

    /**
     * 订单发货(未拆单)
     * @param $params
     */
    public function orderSingleExpress($tid, $out_stype, $out_sid, $kdt_id)
    {
        $request_params = [
            'tid' => $tid,
            'out_stype' => $out_stype,
            'out_sid' => $out_sid,
        ];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'orderSingleExpress',
            'storeID' => $kdt_id
        ]);
    }

    /**
     * 订单发货(拆单)
     * @param $params
     */
    public function orderBatchExpress($params)
    {
        $request_params = [
            'tid' => $params['youzan_order_sn'],
            'oid' => $params['youzan_sub_order_sn'],
            'ex_packages' => [
                'num' => $params['num'],
                'express' => [
                    'express_id' => $params['express_id'],
                    'express_name' => $params['express_name'],
                    'express_no' => $params['express_no'],
                ],
            ]
        ];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'orderBatchExpress',
            'storeID' => $params['kdt_id']
        ]);
    }

    /**
     * 新增商品(一般贸易)
     * @param $params
     */
    public function insertNormalGoods($params, $kdt_id)
    {
        $request_params = array_merge([
            'item_type'  => 0, //商品类型，0-实物商品,60-虚拟商品,61-电子卡劵，63-茶饮烘焙 必填
            'is_display' => 0, //是否上架商品，1—上架商品，0—不上架商品(管理端显示为仓库中)，新增若不传该字段默认传1
            // 'hide_stock' => 0 是否隐藏商品库存，在商品展示时不显示商品的库存，0-显示库存，1-不显示库存，默认0
            'item_delivery_param' => [
                'postage' => 0,
                'delivery_setting' => [
                    'express' => true
                ]
            ]
        ], $params);
        return $this->execute([
            'data'    => ['param' => $request_params],
            'method'  => 'addGoods',
            'storeID' => $kdt_id
        ]);
    }

    /**
     * 新增商品(一般贸易)
     * @param $params
     */
    public function editNormalGoods($params, $kdt_id)
    {
        $request_params = ['param' => $params];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'editGoods',
            'storeID' => $kdt_id
        ]);
    }



    /**
     * 新增商品(海淘)
     * @param $params
     */
    public function insertHaiTaoGoods($params, $kdt_id)
    {
        $haitao_params = [
            'portCode' => 'SZ', // todoluoshumai // 写死测试
            'haiTaoTradeMode' => $params['goods_type'] == 1 ? 1210 : 9610,
            'tariffRule' => $params['has_rate'],
            // 'tariffRate' => $params['has_rate'] == 1 ? 0 : $params['tax_rate'], //非白名单店铺，海淘商品不能设置税率
            'sourceCountryCode' => 984000,
        ];

        /* if($params['has_rate'] == 0){
            $haitao_params['tariffRate'] = $params['tax_rate'] * 100;
        } */
        
        $haitao_params['tariffRate'] = $params['tax_rate'] * 100;

        $request_params = [
            'desc'          => $params['desc'],
            'need_customs_check' => true, //是否进行海淘身份认证
            'need_customs_info'  => true, //是否需要身份认证信息
            'price'              => $params['price'], //价格 单位:分
            'title'              => $params['title'], //商品标题。不能超过100字，受违禁词控制
            'is_display'         => 0, //是否上架商品，1—上架商品，0—不上架商品(管理端显示为仓库中)，新增若不传该字段默认传1
            'origin_price'       => $params['origin_price'],
            'item_sku_extends' => json_encode([
                [
                    "cost_price" => $params['cost_price'],
                    's1' => 0,
                    's2' => 0,
                    's3' => 0,
                    's4' => 0,
                    's5' => 0,
                ]
            ]),
            'hai_tao_param' => json_encode($haitao_params),
            'picture_ids' => $params['images'],
            'item_no' => $params['item_no'],
            'quantity'=> $params['quantity'],
        ];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'addGoodsHaiTao',
            'storeID' => $kdt_id
        ]);
    }

    /**
     * 编辑商品(海淘)
     * @param $params
     */
    public function editHaiTaoGoods($params, $kdt_id)
    {

        $haitao_params = [
            'portCode'          => 'SZ', // todoluoshumai // 写死测试
            'haiTaoTradeMode'   => $params['goods_type'] == 1 ? 1210 : 9610,
            'tariffRule'        => $params['has_rate'],
            // 'tariffRate' => $params['has_rate'] == 1 ? 0 : $params['tax_rate'], //非白名单店铺，海淘商品不能设置税率
            'sourceCountryCode' => 984000,
        ];
        
        //只能以不含税方式推送
        if($params['has_rate'] == 0){
            $haitao_params['tariffRate'] = $params['tax_rate'] * 100;
        }

        $request_params = [
            'item_id'            => $params['item_id'],
            'desc'               => $params['desc'],
            'need_customs_check' => true, //是否进行海淘身份认证
            'need_customs_info'  => true, //是否需要身份认证信息
            // 'price'              => $params['price'], //价格 单位:分
            'title'              => $params['title'], //商品标题。不能超过100字，受违禁词控制
            // 'is_display'         => 0, //是否上架商品，1—上架商品，0—不上架商品(管理端显示为仓库中)，新增若不传该字段默认传1
            // 'origin_price'       => $params['origin_price'],
            'item_sku_extends' => json_encode([
                [
                    "cost_price" => $params['cost_price'],
                    's1' => 0,
                    's2' => 0,
                    's3' => 0,
                    's4' => 0,
                    's5' => 0,
                ]
            ]),
            'hai_tao_param' => json_encode($haitao_params),
            'quantity'=> $params['quantity'],
        ];
        return $this->execute([
            'data'    => $request_params,
            'method'  => 'editGoodsHaiTao',
            'storeID' => $kdt_id
        ]);
    }


    public function updateGoodsStatus($goodsId,$kdt_id)
    {
        return $this->execute([
            'data'    => [
                'item_id' => $goodsId
            ],
            'method'  => 'delGoods',
            'storeID' => $kdt_id
        ]);

    }


    public function updateGoodsDown($goodsId,$kdt_id)
    {
        return $this->execute([
            'data'    => [
                'item_id'  => $goodsId,
                'quantity' => 0
            ],
            'method'  => 'updateQuantity',
            'storeID' => $kdt_id
        ]);

    }


    /** 
     * 获取Token
     * @param [type] $storeID
     * @return array
     */
    private function getToken($storeID)
    {
        $redis = $this->getRedisObj();
        //根据Redis获取Token 
        $access_token = $redis->get(self::TOKEN_PREFIX . $storeID);
        if (!empty($access_token)) {
            return Normal::returnCode(Normal::SUC, '获取Token成功', $access_token);
        }
        //去数据库中查询Token
        $storeInfoObj = PddToken::instance()->where([
            'mall_id' => $storeID
        ])->first();
        if (empty($storeInfoObj)) {
            return Normal::returnCode(Normal::FAIL, '找不到相关的店铺');
        }
        $storeInfo = $storeInfoObj->toArray();
        $youzanTokenInfo = json_decode($storeInfo['info'],true);
        $currentTime = (time() + 600 ) * 1000; // 当前时间+10分钟 如果超过过期时间 那么就过期
        if ($youzanTokenInfo['expires'] <= $currentTime) {
            $response = $this->refreshToken($youzanTokenInfo['refresh_token']);
            if ($response['code'] != Normal::SUC) {
                return Normal::returnCode(Normal::FAIL, '授权失败,重新获取Token异常');
            }
            $responseData = $response['data'];
            PddToken::instance()->edit(
                [
                    'mall_id' => $storeID
                ],
                [
                    'token' => $responseData['access_token'],
                    'info' => json_encode($responseData),
                    'md' => time()
                ]
            );
            //这里保存进redis
            $expire = (int)(bcdiv((bcsub($responseData['expires'],(string)$currentTime)),1000));
            $redis->setex(self::TOKEN_PREFIX . $storeID, $expire, $responseData['access_token']);
            return Normal::returnCode(Normal::SUC, '获取Token成功', $responseData['access_token']);
        }
        $expire = (int)(bcdiv((bcsub($youzanTokenInfo['expires'],(string)$currentTime)),1000));
        $redis->setex(self::TOKEN_PREFIX . $storeID, $expire, $storeInfo['token']);
        return Normal::returnCode(Normal::SUC, '获取Token成功', $storeInfo['token']);
    }

    private function execute($params)
    {
        if (empty($params['data'])) {
            return Normal::returnCode(Normal::FAIL, "数据不能为空");
        }
        if (empty($params['method'])) {
            return Normal::returnCode(Normal::FAIL, "方法不能为空");
        }
        if (empty($params['storeID'])) {
            return Normal::returnCode(Normal::FAIL, "店铺ID不能为空");
        }
        if (!isset($this->routeMaps[$params['method']])) {
            return Normal::returnCode(Normal::FAIL, "未找到路由");
        }
        $token = $this->getToken($params['storeID']);
        if ($token['code'] != Normal::SUC) {
            return Normal::returnCode(Normal::FAIL, "获取token失败");
        }
        $url = $this->apiUrl . $this->routeMaps[$params['method']] . '?access_token=' . $token['data'];
        $start_time = microtime(true);
        $result = Http::apiRequest($url, $params['data'], 'post', $this->header, 30, false, 'json');
        $this->addMicroServiceLog($params['method'], $url, $params['data'], Http::getHttpCode(), $result, $start_time);
        $response = json_decode($result, true);
        if (!isset($response['code']) && isset($response['gw_err_resp'])) {
            $response = Normal::returnCode($response['gw_err_resp']['err_code'], $response['gw_err_resp']['err_msg']);
        }
        return $response;
    }

    private function executeAuth($params)
    {
        if (empty($params['data'])) {
            return Normal::returnCode(Normal::FAIL, "数据不能为空");
        }
        $start_time = microtime(true);
        $result = Http::apiRequest($this->authUrl, $params['data'], 'post', $this->header, 30, false, 'json');
        $response = json_decode($result, true);
        $this->addMicroServiceLog('auth', $this->authUrl, $params['data'], Http::getHttpCode(), $result, $start_time);
        return $response;
    }

    /**
     * 上次图片请求
     * @param string $url
     * @param string $image
     */
    public function uploadImageCurl($params)
    {
        $token = $this->getToken($params['storeID']);
        if ($token['code'] != Normal::SUC) {
            return Normal::returnCode(Normal::FAIL, "获取token失败");
        }
        $url = $this->apiUrl . $this->routeMaps['uploadImg'] . '?access_token=' . $token['data'];
        $start_time = microtime(true);
        $curl = curl_init();
        $ext = strtolower(pathinfo($params['images'], PATHINFO_EXTENSION));
        curl_setopt_array($curl, array(
            CURLOPT_URL             => $url,
            CURLOPT_RETURNTRANSFER  => true,
            CURLOPT_ENCODING        => '',
            CURLOPT_MAXREDIRS       => 10,
            CURLOPT_TIMEOUT         => 30,
            CURLOPT_FOLLOWLOCATION  => true,
            CURLOPT_HTTP_VERSION    => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST   => 'POST',
            CURLOPT_POSTFIELDS      => [
                'image'=> new \CURLFILE($params['images'],$ext,basename($params['images']))
            ],
        ));
        $response = curl_exec($curl);
        curl_close($curl);
        
        //写入日志
        $this->addMicroServiceLog('uploadImg', $url, json_encode(['image'=>$params['images']],JSON_UNESCAPED_UNICODE), 200, $response, $start_time);
        return @json_decode($response,true);
    }

    /**
     * micro_service_log表添加日志
     * @param [type] $method
     * @param [type] $url
     * @param [type] $requestData
     * @param [type] $httpCode
     * @param [type] $res
     * @param [type] $start_time
     * @return void
     * @author luoshumai
     */
    protected static function addMicroServiceLog($method, $url, $requestData, $httpCode, $res, $start_time)
    {
       //写入日志
       MicroServiceLog::instance()->addLog([
        'interface_code'    => 'YouZan_'.$method,
        'request_url'       => $url,
        'request_param'     => json_encode($requestData,JSON_UNESCAPED_UNICODE),
        'response_code'     => $httpCode,
        'response_data'     => $res,
        'req_used_time'     => microtime(true) - $start_time,
    ]);
    }
}
